
#pragma once

// -----------------------------------------------------------------------------

#include "Win32.String.h"

namespace Kif
{
namespace Win32
{
namespace Text
{

class ParseResults
{
public:
   Kif::Win32::String *Strings;
   int Count;

   ParseResults()
   {
      Count = 0;
      Strings = NULL;
   }  // end of ParseResults (ctor)

  ~ParseResults()
   {
      delete Strings;
   }  // end of ~ParseResults (dtor)

}  ;  // end of ParseResults

template<typename T>
class Token
{
public:

   // input buffer
   T *InputBuffer;
   size_t BufferLength;

   // scanned token buffer
   size_t MaxTokenLength;
   T *TokenBuffer;
   size_t TokenLength;

   inline void SetInputBuffer(T *inputBuffer, size_t bufferLength)
   {
      InputBuffer = inputBuffer;
      BufferLength = bufferLength;
   }

   inline void SetTokenBuffer(T *inputBuffer, size_t bufferLength)
   {
      TokenBuffer = inputBuffer;
      MaxTokenLength = bufferLength;
   }

   Token(T *inputBuffer, size_t bufferLength,
         T *tokenBuffer, size_t tokenLength)
   {
      TokenLength = 0;
      SetInputBuffer(inputBuffer, bufferLength);
      SetTokenBuffer(tokenBuffer, tokenLength);
   }

   Token(T *tokenBuffer, size_t tokenLength)
   {
      TokenLength  = 0;
      InputBuffer  = NULL;
      BufferLength = -1;
      SetTokenBuffer(tokenBuffer, tokenLength);
   }

   T *NextToken();

   long ToLong();
   double ToDouble();
}  ;  // end of Token

class Parse
{
public:

   static ParseResults *GetKeyValueStrings(TCHAR *buffer, size_t bufferLength);
   static inline ParseResults *GetKeyValueStrings(Kif::Win32::String &string)
   {
      return(GetKeyValueStrings(string.GetBuffer(),string.GetLength()));
   }  // end of GetKeyValueStrings
   static inline ParseResults *GetKeyValueStrings(Kif::Win32::String *string)
   {
      if (string == NULL)
         return(NULL);
      return(GetKeyValueStrings(string->GetBuffer(),string->GetLength()));
   }  // end of GetKeyValueStrings

   template <class T> static bool IsDelimeter(T *buff)
   {
      return((*buff == 0x0d) && (*(buff + 1) == 0x0a));
   }

   template <class T> static T *SkipTralingBlanks(T *buff)
   {
      while ((*buff != NULL) && ((*buff == ' ') || (*buff < ' ')))
         buff++;
      return(buff);
   }  // end of SkipTralingBlanks

   template <class T> static T *SkipTralingNonePrintables(T *buff)
   {
      while ((*buff != NULL) && (*buff < ' '))
         buff++;
      return(buff);
   }  // end of SkipTralingNonePrintables

   template <class T> static T *SkipToken(T *buff)
   {
      while ((*buff != NULL) && (*buff >= ' '))
         buff++;
      return(Parse::SkipTralingNonePrintables(buff));
   }  // end of SkipToken

   template <class T> static T *GetToken(T *outBuff, int outMaxLength, T *inBuff)
   {
      int len = 0;
      while ((*inBuff != NULL) && (*inBuff >= ' '))
      {
         *outBuff = *inBuff;
         outBuff++;
         inBuff++;
         if (len >= outMaxLength)
            throw L"No more space in string";
         len++;
      }

      len++;
      if (len >= outMaxLength)
         throw L"No more space in string";
      *outBuff = NULL;

      inBuff = SkipTralingNonePrintables(inBuff);
      return(inBuff);
   }  // end of GetToken

   template <class T> static T *GetToken(Token<T> &token)
   {
      T *outBuff = token.TokenBuffer;

      token.TokenLength = 0;
      token.InputBuffer = SkipTralingBlanks(token.InputBuffer);

      while ((*token.InputBuffer != NULL) && (*token.InputBuffer > ' '))
      {
         *outBuff = *token.InputBuffer;
         outBuff++;
         token.InputBuffer++;
         if (token.TokenLength >= token.MaxTokenLength)
            throw L"No more space in string";
         token.TokenLength++;
      }

      token.TokenLength++;
      if (token.TokenLength >= token.MaxTokenLength)
         throw L"No more space in string";
      *outBuff = NULL;

      token.InputBuffer = SkipTralingNonePrintables(token.InputBuffer);
      return(token.InputBuffer);
   }  // end of GetToken

}  ;  // end of Kif::Text::Parse class

}  // end of Kif::Win32::Text namespace
}  // end of Kif::Win32 namespace
}  // end of Kif namespace
